<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
<HTML
><HEAD
><TITLE
>Of Zeros and Nulls</TITLE
><META
NAME="GENERATOR"
CONTENT="Modular DocBook HTML Stylesheet Version 1.7"><LINK
REL="HOME"
TITLE="Advanced Bash-Scripting Guide"
HREF="index.html"><LINK
REL="UP"
TITLE="Advanced Topics"
HREF="part5.html"><LINK
REL="PREVIOUS"
TITLE="Network Programming"
HREF="networkprogramming.html"><LINK
REL="NEXT"
TITLE="Debugging"
HREF="debugging.html"></HEAD
><BODY
CLASS="CHAPTER"
BGCOLOR="#FFFFFF"
TEXT="#000000"
LINK="#0000FF"
VLINK="#840084"
ALINK="#0000FF"
><DIV
CLASS="NAVHEADER"
><TABLE
SUMMARY="Header navigation table"
WIDTH="100%"
BORDER="0"
CELLPADDING="0"
CELLSPACING="0"
><TR
><TH
COLSPAN="3"
ALIGN="center"
>Advanced Bash-Scripting Guide: </TH
></TR
><TR
><TD
WIDTH="10%"
ALIGN="left"
VALIGN="bottom"
><A
HREF="networkprogramming.html"
ACCESSKEY="P"
>Prev</A
></TD
><TD
WIDTH="80%"
ALIGN="center"
VALIGN="bottom"
></TD
><TD
WIDTH="10%"
ALIGN="right"
VALIGN="bottom"
><A
HREF="debugging.html"
ACCESSKEY="N"
>Next</A
></TD
></TR
></TABLE
><HR
ALIGN="LEFT"
WIDTH="100%"></DIV
><DIV
CLASS="CHAPTER"
><H1
><A
NAME="ZEROS"
></A
>Chapter 31. Of Zeros and Nulls</H1
><TABLE
BORDER="0"
WIDTH="100%"
CELLSPACING="0"
CELLPADDING="0"
CLASS="EPIGRAPH"
><TR
><TD
WIDTH="45%"
>&nbsp;</TD
><TD
WIDTH="45%"
ALIGN="LEFT"
VALIGN="TOP"
><I
><P
><I
>Faultily faultless, icily regular, splendidly null</I
></P
><P
><I
>Dead perfection; no more.</I
></P
><P
><I
>--Alfred Lord Tennyson</I
></P
></I
></TD
></TR
></TABLE
><P
><A
NAME="ZEROSREF"
></A
></P
><P
></P
><DIV
CLASS="VARIABLELIST"
><P
><B
><A
NAME="ZERONULL1"
></A
><TT
CLASS="FILENAME"
>/dev/zero</TT
>
          ... <TT
CLASS="FILENAME"
>/dev/null</TT
></B
></P
><DL
><DT
><A
NAME="DEVNULLREF"
></A
>Uses of
	    <TT
CLASS="FILENAME"
>/dev/null</TT
></DT
><DD
><P
>Think of <TT
CLASS="FILENAME"
>/dev/null</TT
> as a <I
CLASS="FIRSTTERM"
>black
		hole</I
>. It is essentially the equivalent of
		a write-only file. Everything written to it disappears.
		Attempts to read or output from it result in nothing. All
		the same, <TT
CLASS="FILENAME"
>/dev/null</TT
> can be quite
		useful from both the command-line and in scripts.</P
><P
>Suppressing <TT
CLASS="FILENAME"
>stdout</TT
>.
	      <TABLE
BORDER="0"
BGCOLOR="#E0E0E0"
WIDTH="90%"
><TR
><TD
><FONT
COLOR="#000000"
><PRE
CLASS="PROGRAMLISTING"
>cat $filename &#62;/dev/null
# Contents of the file will not list to stdout.</PRE
></FONT
></TD
></TR
></TABLE
>
            </P
><P
>Suppressing <TT
CLASS="FILENAME"
>stderr</TT
>
	      (from <A
HREF="moreadv.html#EX57"
>Example 16-3</A
>).
	      <TABLE
BORDER="0"
BGCOLOR="#E0E0E0"
WIDTH="90%"
><TR
><TD
><FONT
COLOR="#000000"
><PRE
CLASS="PROGRAMLISTING"
>rm $badname 2&#62;/dev/null
#           So error messages [stderr] deep-sixed.</PRE
></FONT
></TD
></TR
></TABLE
>
	    </P
><P
>Suppressing output from <EM
>both</EM
>
	      <TT
CLASS="FILENAME"
>stdout</TT
> and <TT
CLASS="FILENAME"
>stderr</TT
>.
	      <TABLE
BORDER="0"
BGCOLOR="#E0E0E0"
WIDTH="90%"
><TR
><TD
><FONT
COLOR="#000000"
><PRE
CLASS="PROGRAMLISTING"
>cat $filename 2&#62;/dev/null &#62;/dev/null
# If "$filename" does not exist, there will be no error message output.
# If "$filename" does exist, the contents of the file will not list to stdout.
# Therefore, no output at all will result from the above line of code.
#
#  This can be useful in situations where the return code from a command
#+ needs to be tested, but no output is desired.
#
# cat $filename &#38;&#62;/dev/null
#     also works, as Baris Cicek points out.</PRE
></FONT
></TD
></TR
></TABLE
>
	    </P
><P
>Deleting contents of a file, but preserving the file itself, with
	      all attendant permissions (from <A
HREF="sha-bang.html#EX1"
>Example 2-1</A
> and <A
HREF="sha-bang.html#EX2"
>Example 2-3</A
>):
	      <TABLE
BORDER="0"
BGCOLOR="#E0E0E0"
WIDTH="90%"
><TR
><TD
><FONT
COLOR="#000000"
><PRE
CLASS="PROGRAMLISTING"
>cat /dev/null &#62; /var/log/messages
#  : &#62; /var/log/messages   has same effect, but does not spawn a new process.

cat /dev/null &#62; /var/log/wtmp</PRE
></FONT
></TD
></TR
></TABLE
>
	      </P
><P
>Automatically emptying the contents of a logfile
	      (especially good for dealing with those nasty
	      <SPAN
CLASS="QUOTE"
>"cookies"</SPAN
> sent by commercial Web sites):</P
><DIV
CLASS="EXAMPLE"
><A
NAME="COOKIES"
></A
><P
><B
>Example 31-1. Hiding the cookie jar</B
></P
><TABLE
BORDER="0"
BGCOLOR="#E0E0E0"
WIDTH="90%"
><TR
><TD
><FONT
COLOR="#000000"
><PRE
CLASS="PROGRAMLISTING"
># Obsolete Netscape browser.
# Same principle applies to newer browsers.

if [ -f ~/.netscape/cookies ]  # Remove, if exists.
then
  rm -f ~/.netscape/cookies
fi

ln -s /dev/null ~/.netscape/cookies
# All cookies now get sent to a black hole, rather than saved to disk.</PRE
></FONT
></TD
></TR
></TABLE
></DIV
></DD
><DT
><A
NAME="ZEROSREF1"
></A
>Uses of <TT
CLASS="FILENAME"
>/dev/zero</TT
></DT
><DD
><P
>Like <TT
CLASS="FILENAME"
>/dev/null</TT
>,
	      <TT
CLASS="FILENAME"
>/dev/zero</TT
> is a pseudo-device file, but
	      it actually produces a stream of nulls
	      (<EM
>binary</EM
> zeros, not the <A
HREF="special-chars.html#ASCIIDEF"
>ASCII</A
> kind). Output written
	      to <TT
CLASS="FILENAME"
>/dev/zero</TT
> disappears, and it is
	      fairly difficult to actually read the nulls emitted there,
	      though it can be done with <A
HREF="extmisc.html#ODREF"
>od</A
>
	      or a hex editor. <A
NAME="SWAPFILEREF"
></A
>The chief use of
	      <TT
CLASS="FILENAME"
>/dev/zero</TT
> is creating an initialized
	      dummy file of predetermined length intended as a temporary
	      swap file.</P
><DIV
CLASS="EXAMPLE"
><A
NAME="EX73"
></A
><P
><B
>Example 31-2. Setting up a swapfile using <TT
CLASS="FILENAME"
>/dev/zero</TT
></B
></P
><TABLE
BORDER="0"
BGCOLOR="#E0E0E0"
WIDTH="90%"
><TR
><TD
><FONT
COLOR="#000000"
><PRE
CLASS="PROGRAMLISTING"
>#!/bin/bash
# Creating a swap file.

#  A swap file provides a temporary storage cache
#+ which helps speed up certain filesystem operations.

ROOT_UID=0         # Root has $UID 0.
E_WRONG_USER=85    # Not root?

FILE=/swap
BLOCKSIZE=1024
MINBLOCKS=40
SUCCESS=0


# This script must be run as root.
if [ "$UID" -ne "$ROOT_UID" ]
then
  echo; echo "You must be root to run this script."; echo
  exit $E_WRONG_USER
fi  
  

blocks=${1:-$MINBLOCKS}          #  Set to default of 40 blocks,
                                 #+ if nothing specified on command-line.
# This is the equivalent of the command block below.
# --------------------------------------------------
# if [ -n "$1" ]
# then
#   blocks=$1
# else
#   blocks=$MINBLOCKS
# fi
# --------------------------------------------------


if [ "$blocks" -lt $MINBLOCKS ]
then
  blocks=$MINBLOCKS              # Must be at least 40 blocks long.
fi  


######################################################################
echo "Creating swap file of size $blocks blocks (KB)."
dd if=/dev/zero of=$FILE bs=$BLOCKSIZE count=$blocks  # Zero out file.
mkswap $FILE $blocks             # Designate it a swap file.
swapon $FILE                     # Activate swap file.
retcode=$?                       # Everything worked?
#  Note that if one or more of these commands fails,
#+ then it could cause nasty problems.
######################################################################

#  Exercise:
#  Rewrite the above block of code so that if it does not execute
#+ successfully, then:
#    1) an error message is echoed to stderr,
#    2) all temporary files are cleaned up, and
#    3) the script exits in an orderly fashion with an
#+      appropriate error code.

echo "Swap file created and activated."

exit $retcode</PRE
></FONT
></TD
></TR
></TABLE
></DIV
><P
>Another application of <TT
CLASS="FILENAME"
>/dev/zero</TT
>
	      is to <SPAN
CLASS="QUOTE"
>"zero out"</SPAN
> a file of a designated
	      size for a special purpose, such as mounting a filesystem
	      on a <A
HREF="devref1.html#LOOPBACKREF"
>loopback device</A
>
	      (see <A
HREF="system.html#CREATEFS"
>Example 17-8</A
>) or <SPAN
CLASS="QUOTE"
>"securely"</SPAN
>
	      deleting a file (see <A
HREF="extmisc.html#BLOTOUT"
>Example 16-61</A
>).</P
><DIV
CLASS="EXAMPLE"
><A
NAME="RAMDISK"
></A
><P
><B
>Example 31-3. Creating a ramdisk</B
></P
><TABLE
BORDER="0"
BGCOLOR="#E0E0E0"
WIDTH="90%"
><TR
><TD
><FONT
COLOR="#000000"
><PRE
CLASS="PROGRAMLISTING"
>#!/bin/bash
# ramdisk.sh

#  A "ramdisk" is a segment of system RAM memory
#+ which acts as if it were a filesystem.
#  Its advantage is very fast access (read/write time).
#  Disadvantages: volatility, loss of data on reboot or powerdown,
#+                less RAM available to system.
#
#  Of what use is a ramdisk?
#  Keeping a large dataset, such as a table or dictionary on ramdisk,
#+ speeds up data lookup, since memory access is much faster than disk access.


E_NON_ROOT_USER=70             # Must run as root.
ROOTUSER_NAME=root

MOUNTPT=/mnt/ramdisk           # Create with mkdir /mnt/ramdisk.
SIZE=2000                      # 2K blocks (change as appropriate)
BLOCKSIZE=1024                 # 1K (1024 byte) block size
DEVICE=/dev/ram0               # First ram device

username=`id -nu`
if [ "$username" != "$ROOTUSER_NAME" ]
then
  echo "Must be root to run \"`basename $0`\"."
  exit $E_NON_ROOT_USER
fi

if [ ! -d "$MOUNTPT" ]         #  Test whether mount point already there,
then                           #+ so no error if this script is run
  mkdir $MOUNTPT               #+ multiple times.
fi

##############################################################################
dd if=/dev/zero of=$DEVICE count=$SIZE bs=$BLOCKSIZE  # Zero out RAM device.
                                                      # Why is this necessary?
mke2fs $DEVICE                 # Create an ext2 filesystem on it.
mount $DEVICE $MOUNTPT         # Mount it.
chmod 777 $MOUNTPT             # Enables ordinary user to access ramdisk.
                               # However, must be root to unmount it.
##############################################################################
# Need to test whether above commands succeed. Could cause problems otherwise.
# Exercise: modify this script to make it safer.

echo "\"$MOUNTPT\" now available for use."
# The ramdisk is now accessible for storing files, even by an ordinary user.

#  Caution, the ramdisk is volatile, and its contents will disappear
#+ on reboot or power loss.
#  Copy anything you want saved to a regular directory.

# After reboot, run this script to again set up ramdisk.
# Remounting /mnt/ramdisk without the other steps will not work.

#  Suitably modified, this script can by invoked in /etc/rc.d/rc.local,
#+ to set up ramdisk automatically at bootup.
#  That may be appropriate on, for example, a database server.

exit 0</PRE
></FONT
></TD
></TR
></TABLE
></DIV
><P
>In addition to all the above,
	      <TT
CLASS="FILENAME"
>/dev/zero</TT
> is needed by ELF
	      (<I
CLASS="FIRSTTERM"
>Executable and Linking Format</I
>)
	      UNIX/Linux binaries.</P
></DD
></DL
></DIV
></DIV
><DIV
CLASS="NAVFOOTER"
><HR
ALIGN="LEFT"
WIDTH="100%"><TABLE
SUMMARY="Footer navigation table"
WIDTH="100%"
BORDER="0"
CELLPADDING="0"
CELLSPACING="0"
><TR
><TD
WIDTH="33%"
ALIGN="left"
VALIGN="top"
><A
HREF="networkprogramming.html"
ACCESSKEY="P"
>Prev</A
></TD
><TD
WIDTH="34%"
ALIGN="center"
VALIGN="top"
><A
HREF="index.html"
ACCESSKEY="H"
>Home</A
></TD
><TD
WIDTH="33%"
ALIGN="right"
VALIGN="top"
><A
HREF="debugging.html"
ACCESSKEY="N"
>Next</A
></TD
></TR
><TR
><TD
WIDTH="33%"
ALIGN="left"
VALIGN="top"
>Network Programming</TD
><TD
WIDTH="34%"
ALIGN="center"
VALIGN="top"
><A
HREF="part5.html"
ACCESSKEY="U"
>Up</A
></TD
><TD
WIDTH="33%"
ALIGN="right"
VALIGN="top"
>Debugging</TD
></TR
></TABLE
></DIV
></BODY
></HTML
>